package top.hbq;


import java.util.*;
public class Game{

    private final int chessboard_size = 8;
    private int level; // Opponent's chess strength (1: elementary, 2: intermediate, 3: advanced)
    private boolean firstMove; // Whether to go first
    private int[][] chessboard = new int[chessboard_size][chessboard_size];
    private int id; // 当前该谁下（1：黑棋，2：白棋）
    private int count;
    private int tempLevel;
    private int count_black;
    private int count_white;
    private int skipcount;
    private MyPoint pos = null;
    private boolean temp = true;

    public Game(int level, boolean firstMove){
        this.level = level;
        this.firstMove = firstMove;
        init();
        if (!firstMove) {
            computerOperate();
        }
    }

    public void init() {
        for (int i = 0; i < chessboard_size; i++) {
            for (int j = 0; j < chessboard_size; j++) {
                chessboard[i][j] = 0;
            }
        }
        chessboard[chessboard_size / 2 - 1][chessboard_size / 2] = 1;
        chessboard[chessboard_size / 2][chessboard_size / 2 - 1] = 1;
        chessboard[chessboard_size / 2 - 1][chessboard_size / 2 - 1] = 2;
        chessboard[chessboard_size / 2][chessboard_size / 2] = 2;
        id = 1;
        count = 4;
        count_black = count_white = 2;
        skipcount = 0;
    }



    /**
     * Only use one direction to judge whether you can place a child at that position
     *
     * @param point
     *            The position of the point on the board
     * @param dx
     *            x-direction offset
     * @param dy
     *            y-direction offset
     * @param flag
     *            If the location to be judged is close to (x, y), take flag=0, otherwise take flag=1
     * @return
     */
    public boolean legalOnPosition(MyPoint point, int dx, int dy, int flag) {
        int self = id;
        int em = id % 2 + 1;
        point.setX(point.getX() + dx);
        point.setY(point.getY() + dy);
        if (point.getX() < 0 || point.getX() >= chessboard_size
                || point.getY() < 0 || point.getY() >= chessboard_size) {
            return false;
        }
        // If the position is your own pawn, if there are one or more opponent pawns between the position and the position to be played, return true, otherwise return false
        if (chessboard[point.getX()][point.getY()] == self) {
            if (flag == 1) {
                return true;
            }
            return false;
        }
        // If the position is the opponent's pawn, call this method recursively to find the result
        if (chessboard[point.getX()][point.getY()] == em) {
            return legalOnPosition(point, dx, dy, 1);
        }
        return false;
    }

    /**
     * Determine whether the position cannot be placed
     *
     * @param point
     *            The position of the point on the board
     * @return true: can not be placed, false: can be placed
     */
    public boolean illegal(MyPoint point) {
        int x = point.getX();
        int y = point.getY();
        if (chessboard[x][y] != 0) {
            return true;
        }
        for (int i = -1; i <= 1; i++) {
            for (int j = -1; j <= 1; j++) {
                if (i == 0 && j == 0) {
                    continue;
                }
                if (legalOnPosition(new MyPoint(x, y), i, j, 0)) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * Determine if there is nowhere to go
     *
     * @return
     */
    public boolean skip() {
        for (int i = 0; i < chessboard_size; i++) {
            for (int j = 0; j < chessboard_size; j++) {
                if (chessboard[i][j] != 0) {
                    continue;
                }
                if (!illegal(new MyPoint(i, j))) {
                    return false;
                }
            }
        }
        return true;
    }

    public boolean isEnd() {
        if (count >= chessboard_size * chessboard_size || skipcount >= 2) {
            return true;
        }
        return false;
    }
    /**
     * Game display method
     */
    public void showGame(){
        System.out.println("Current game：");
        System.out.println(" \ta\tb\tc\td\te\tf\tg\th");
        for (int i = 0; i < 8; i++) {
            System.out.print((i+1)+"\t");
            for (int j = 0; j < 8; j++) {
                if (chessboard[i][j]==0){
                    System.out.print("*\t");
                }else if (chessboard[i][j]==1){
                    System.out.print("B\t");
                }else{
                    System.out.print("W\t");
                }
            }
            System.out.println();
        }
    }
    /**
     * Drop and flip
     *
     * @param point
     *            Placement
     */
    public void revergal(MyPoint point) {
        int self = id;
        int em = id % 2 + 1;
        int x = point.getX();
        int y = point.getY();
        int m, n;
        chessboard[x][y] = self;
        count++;
        if (self == 1) {
            count_black++;
        } else {
            count_white++;
        }
        skipcount = 0;
        for (int i = -1; i <= 1; i++) {
            for (int j = -1; j <= 1; j++) {
                if (i == 0 && j == 0) {
                    continue;
                }
                if (legalOnPosition(new MyPoint(x, y), i, j, 0)) {
                    m = x + i;
                    n = y + j;
                    while (chessboard[m][n] == em) {
                        chessboard[m][n] = self;
                        if (self == 1) {
                            count_black++;
                            count_white--;
                        } else {
                            count_white++;
                            count_black--;
                        }
                        m += i;
                        n += j;
                    }
                }
            }
        }
        id = id % 2 + 1;
        if (!isEnd() && skip()) {
            skipcount++;
            id = id % 2 + 1;
            if (skipcount == 1 && !skip()) {
                if (id == 1) {
                    System.out.println("White has nowhere to play, black continues!");
                } else {
                    System.out.println("Black has nowhere to play, white continues!");
                }
                if (firstMove && id == 1 || !firstMove && id == 2) {
                    return;
                }
            } else if (skipcount == 1 && skip()) {
                skipcount++;
            }
        }
        if (!isEnd()) {
            if (firstMove && id == 2 || !firstMove && id == 1) {
                computerOperate();
            }
        }
    }

    public void computerOperate() {
        MyPoint point = new MyPoint(0, 0);
        LinkedList<MyPoint> legalPoints = new LinkedList<MyPoint>();
        for (int i = 0; i < chessboard_size; i++) {
            for (int j = 0; j < chessboard_size; j++) {
                if (chessboard[i][j] != 0) {
                    continue;
                }
                if (!illegal(new MyPoint(i, j))) {
                    legalPoints.add(new MyPoint(i, j));
                }
            }
        }
        if (level == 1) {
            BeginnerAlgorithm alg1 = new BeginnerAlgorithm(id,
                    chessboard, pos, legalPoints, count);
            point = alg1.getPositionToTurn();
        } else if (level == 2) {
            IntermediateAlgorithm alg2 = new IntermediateAlgorithm(id,
                    chessboard, pos, legalPoints, count);
            point = alg2.getPositionToTurn();
        } else {
            ExpertAlgorithm alg3 = new ExpertAlgorithm(id, chessboard,
                    pos, legalPoints, count);
            point = alg3.getPositionToTurn();
        }
        revergal(point);
    }

    public void autoPlay(){
        while (!isEnd()){
            firstMove = ! firstMove;
            computerOperate();
        }
    }
    public void autoPlay(int level){
        this.tempLevel = level;
        while (!isEnd()){
            int tempLevel = this.level;
            this.level = this.tempLevel;
            this.tempLevel = tempLevel;
            firstMove = ! firstMove;
            computerOperate();
        }
    }
    public void pressPoint( MyPoint point) {
        // TODO Auto-generated method stub
        int x = point.getX();
        int y = point.getY();
        if (isEnd() || x < 0 || x >= chessboard_size || y < 0
                || y >= chessboard_size) {
            return;
        }
        if (illegal(point)) {
            System.out.println("The location you choose cannot be placed,Please select again.");
        } else {
            pos = point;
            revergal(pos);
        }
    }
    public void Win(){
        if (count_black > count_white) {
            count_black += chessboard_size * chessboard_size - count;
            System.out.println( "The final points are: Black:" + count_black
                            + ", White:" + count_white + ", Black wins!");
        } else if (count_black < count_white) {
            count_white += chessboard_size * chessboard_size - count;

            System.out.println("The final points are: Black:" + count_black
                            + ", White:" + count_white + ", White wins!");
        } else {
            System.out.println("The final points are: Black:" + count_black
                            + ", White:" + count_white + ", Draw!");
        }
    }
}
